1 /*-------------------------------------------------------------------------------------------------------*\
2 | Adium, Copyright (C) 2001-2005, Adam Iser (adamiser@mac.com | http://www.adiumx.com) |
3 \---------------------------------------------------------------------------------------------------------/
4 | This program is free software; you can redistribute it and/or modify it under the terms of the GNU
5 | General Public License as published by the Free Software Foundation; either version 2 of the License,
6 | or (at your option) any later version.
8 | This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
9 | the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
10 | Public License for more details.
12 | You should have received a copy of the GNU General Public License along with this program; if not,
13 | write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
14 \------------------------------------------------------------------------------------------------------ */
17 Allows easy access to the elements of a dictionary
20 #import "AIDictionaryAdditions.h"
21 #import "AIFileManagerAdditions.h"
23 @implementation NSDictionary (AIDictionaryAdditions)
25 // Returns a dictionary from the owners bundle with the specified name
26 + (NSDictionary *)dictionaryNamed:(NSString *)name forClass:(Class)inClass
28 NSBundle *ownerBundle;
33 ownerBundle = [NSBundle bundleForClass:inClass];
36 dictPath = [ownerBundle pathForResource:name ofType:@"plist"];
37 dict = [NSDictionary dictionaryWithContentsOfFile:dictPath];
42 // returns the dictionary from the specified path
43 + (NSDictionary *)dictionaryAtPath:(NSString *)path withName:(NSString *)name create:(BOOL)create
45 NSParameterAssert(path != nil); NSParameterAssert([path length] != 0);
46 NSParameterAssert(name != nil); NSParameterAssert([name length] != 0);
48 NSDictionary *dictionary = [NSDictionary dictionaryWithContentsOfFile:[[path stringByAppendingPathComponent:name] stringByAppendingPathExtension:@"plist"]];
50 if (!dictionary && create) dictionary = [NSDictionary dictionary];
55 - (BOOL)validateAsPropertyList
58 NSEnumerator *enumerator = [self keyEnumerator];
60 while ((key = [enumerator nextObject])) {
61 if (![key isKindOfClass:[NSString class]]) {
62 NSLog(@"** Dictionary failed validation: %@: Key %@ is a %@ but must be an NSString",
63 self, key, NSStringFromClass([key class]));
67 id value = [self objectForKey:key];
68 Class valueClass = [value class];
69 if (![value isKindOfClass:[NSString class]] &&
70 ![value isKindOfClass:[NSData class]] &&
71 ![value isKindOfClass:[NSNumber class]] &&
72 ![value isKindOfClass:[NSArray class]] &&
73 ![value isKindOfClass:[NSDictionary class]] &&
74 ![value isKindOfClass:[NSDate class]]) {
75 NSLog(@"** Dictionary failed validation: %@: Value %@ is a %@ but must be a string, data, number, array, dictionary, or date",
76 self, value, NSStringFromClass(valueClass));
80 if ([value isKindOfClass:[NSArray class]] ||[value isKindOfClass:[NSDictionary class]]) {
81 BOOL successOfValue = [value validateAsPropertyList];
82 if (validated) validated = successOfValue;
89 // saves this dictionary to the specified path
90 - (BOOL)writeToPath:(NSString *)path withName:(NSString *)name
92 NSParameterAssert(path != nil); NSParameterAssert([path length] != 0);
93 NSParameterAssert(name != nil); NSParameterAssert([name length] != 0);
95 [[NSFileManager defaultManager] createDirectoriesForPath:path]; //make sure the path exists
98 NSString *retainedError = nil;
99 plistData = [NSPropertyListSerialization dataFromPropertyList:self
100 format:NSPropertyListBinaryFormat_v1_0
101 errorDescription:&retainedError];
103 BOOL success = [plistData writeToFile:[[path stringByAppendingPathComponent:name] stringByAppendingPathExtension:@"plist"]
106 NSLog(@"%s: Error writing path %@, name %@ (%@)", __PRETTY_FUNCTION__, path, name, [[path stringByAppendingPathComponent:name] stringByAppendingPathExtension:@"plist"]);
110 NSLog(@"%s: Could not serialize. Error: \"%@\".", retainedError);
111 [self validateAsPropertyList];
113 if (retainedError) [retainedError release];
119 - (NSDictionary *)dictionaryByTranslating:(NSDictionary *)translation adding:(NSDictionary *)addition removing:(NSSet *)removal
121 NSDictionary *result;
123 //only do work if we have work to do.
124 if (translation || addition || removal) {
125 NSMutableDictionary *mutable = [self mutableCopy];
127 [mutable translate:translation add:addition remove:removal];
129 result = [[self class] dictionaryWithDictionary:mutable];
132 result = [[self retain] autorelease];
138 - (NSSet *)allKeysSet {
139 return [NSSet setWithArray:[self allKeys]];
141 - (NSMutableSet *)allKeysMutableSet {
142 return [NSMutableSet setWithArray:[self allKeys]];
145 - (void)compareWithPriorDictionary:(NSDictionary *)other
146 getAddedKeys:(out NSSet **)outAddedKeys
147 getRemovedKeys:(out NSSet **)outRemovedKeys
148 includeChangedKeys:(BOOL)flag
151 if (outAddedKeys) *outAddedKeys = [self allKeysSet];
152 if (outRemovedKeys) *outRemovedKeys = [NSSet set];
154 NSMutableSet *addedKeys = nil;
156 unsigned capacity = [self count];
157 if (flag) capacity += [other count];
158 addedKeys = [NSMutableSet setWithCapacity:capacity];
161 NSMutableSet *removedKeys = nil;
162 if (outRemovedKeys) {
163 unsigned capacity = [other count];
164 if (flag) capacity += [self count];
165 removedKeys = [NSMutableSet setWithCapacity:capacity];
168 NSEnumerator *keysEnum = [self keyEnumerator];
170 while ((key = [keysEnum nextObject])) {
171 id otherObj = [other objectForKey:key];
173 //Not in other, but is in self: Added.
174 [addedKeys addObject:key];
175 } else if(flag && ![otherObj isEqual:[self objectForKey:key]]) {
176 //Exists in both, objects are not equal, and flag is not NO: Different, and we should put the key in both sets to indicate this.
177 [addedKeys addObject:key];
178 [removedKeys addObject:key];
181 if (outAddedKeys) *outAddedKeys = [NSSet setWithSet:addedKeys];
183 if (outRemovedKeys) {
184 keysEnum = [other keyEnumerator];
185 while ((key = [keysEnum nextObject])) {
186 if (![self objectForKey:key]) {
187 //In other, but not in self: Removed.
188 [removedKeys addObject:key];
192 *outRemovedKeys = [NSSet setWithSet:removedKeys];
197 - (NSDictionary *)dictionaryWithIntersectionWithSetOfKeys:(NSSet *)keys
199 NSMutableDictionary *mutableSelf = [self mutableCopy];
200 [mutableSelf intersectSetOfKeys:keys];
201 NSDictionary *result = [NSDictionary dictionaryWithDictionary:mutableSelf];
202 [mutableSelf release];
205 - (NSDictionary *)dictionaryWithDifferenceWithSetOfKeys:(NSSet *)keys
207 NSMutableDictionary *mutableSelf = [self mutableCopy];
208 [mutableSelf minusSetOfKeys:keys];
209 NSDictionary *result = [NSDictionary dictionaryWithDictionary:mutableSelf];
210 [mutableSelf release];
214 - (NSString *)CSSString
216 NSMutableArray *properties = [NSMutableArray arrayWithCapacity:[self count]];
218 NSEnumerator *keysEnum = [self keyEnumerator];
220 while ((key = [keysEnum nextObject])) {
221 [properties addObject:[NSString stringWithFormat:@"%@: %@;", key, [self objectForKey:key]]];
224 return [properties componentsJoinedByString:@" "];
229 @implementation NSMutableDictionary (AIDictionaryAdditions)
231 // returns the dictionary from the specified path
232 + (NSMutableDictionary *)dictionaryAtPath:(NSString *)path withName:(NSString *)name create:(BOOL)create
234 NSMutableDictionary *dictionary;
236 NSParameterAssert(path != nil); NSParameterAssert([path length] != 0);
237 NSParameterAssert(name != nil); NSParameterAssert([name length] != 0);
242 plistData = [[NSData alloc] initWithContentsOfFile:[[path stringByAppendingPathComponent:name] stringByAppendingPathExtension:@"plist"]];
244 dictionary = [NSPropertyListSerialization propertyListFromData:plistData
245 mutabilityOption:NSPropertyListMutableContainers
247 errorDescription:&error];
250 if (!dictionary && create) dictionary = [NSMutableDictionary dictionary];
256 - (void)translate:(NSDictionary *)translation add:(NSDictionary *)addition remove:(NSSet *)removal
258 //only do work if we have work to do.
259 if (translation || addition || removal) {
260 NSDictionary *selfCopy = [self copy];
261 NSEnumerator *keyEnum = [selfCopy keyEnumerator];
264 while ((key = [keyEnum nextObject])) {
265 NSString *newKey = [translation objectForKey:key];
267 [self setObject:[selfCopy objectForKey:key] forKey:newKey];
270 if (removal && [removal containsObject:key]) {
271 [self removeObjectForKey:key];
277 //Add items that aren't in the removal set.
278 keyEnum = [addition keyEnumerator];
279 while ((key = [keyEnum nextObject])) {
280 if (!(removal && [removal containsObject:key])) {
281 [self setObject:[addition objectForKey:key] forKey:key];
287 - (void)intersectSetOfKeys:(NSSet *)keys
289 NSMutableArray *keysToRemove = [NSMutableArray array];
290 NSEnumerator *myKeysEnum = [self keyEnumerator];
292 while ((key = [myKeysEnum nextObject])) {
293 if (![keys containsObject:key]) {
294 [keysToRemove addObject:key];
297 NSEnumerator *deadKeysEnum = [keysToRemove objectEnumerator];
298 while ((key = [deadKeysEnum nextObject])) {
299 [self removeObjectForKey:key];
302 - (void)minusSetOfKeys:(NSSet *)keys
304 NSEnumerator *keysEnum = [keys objectEnumerator];
306 while ((key = [keysEnum nextObject])) {
307 [self removeObjectForKey:key];